package com.stone.stoneanswer.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stone.stoneanswer.common.DeleteRequest;
import com.stone.stoneanswer.constant.CommonConstant;
import com.stone.stoneanswer.mapper.QuestionBankMapper;
import com.stone.stoneanswer.model.dto.questionbank.QuestionBankGetRequest;
import com.stone.stoneanswer.model.dto.questionbank.QuestionBankRecommendRequest;
import com.stone.stoneanswer.model.entity.AnswerResult;
import com.stone.stoneanswer.model.entity.QuestionBank;
import com.stone.stoneanswer.model.entity.User;
import com.stone.stoneanswer.model.vo.QuestionBankVO;
import com.stone.stoneanswer.model.vo.UserVO;
import com.stone.stoneanswer.service.AnswerResultService;
import com.stone.stoneanswer.service.QuestionBankService;
import com.stone.stoneanswer.service.UserService;
import com.stone.stoneanswer.utils.SqlUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 35431
 * @description 针对表【questionBank_bank(题库表)】的数据库操作Service实现
 * @createDate 2025-02-05 18:21:12
 */
@Service
public class QuestionBankServiceImpl extends ServiceImpl<QuestionBankMapper, QuestionBank>
        implements QuestionBankService {

    @Resource
    private UserService userService;

    @Resource
    private QuestionBankMapper questionBankMapper;

    @Resource
    private AnswerResultService answerResultService;

    @Override
    public QuestionBankVO getQuestionBankVO(QuestionBank questionBank, HttpServletRequest request) {
        QuestionBankVO questionBankVO = QuestionBankVO.objToVo(questionBank);
        // 关联查询用户信息
        Long userId = questionBank.getUserId();
        User user = null;
        if (userId != null && userId > 0) {
            user = userService.getById(userId);
        }
        UserVO userVO = userService.getUserVO(user);
        questionBankVO.setUser(userVO);
        // TODO 获取用户的点赞，收藏状态
        User loginUser = userService.getLoginUserPermitNull(request);
        if (loginUser != null) {
            questionBankVO.setIsFavour(true);
            questionBankVO.setIsThumb(true);
        }
        return questionBankVO;
    }

    @Override
    public QueryWrapper<QuestionBank> getQueryWrapper(QuestionBankGetRequest questionBankGetRequest) {
        QueryWrapper<QuestionBank> queryWrapper = new QueryWrapper<>();
        if (questionBankGetRequest == null) {
            return queryWrapper;
        }
        List<String> tags = questionBankGetRequest.getTags();
        Long userId = questionBankGetRequest.getUserId();
        String searchText = questionBankGetRequest.getSearchText();
        String sortField = questionBankGetRequest.getSortField();
        String sortOrder = questionBankGetRequest.getSortOrder();
        Long questionBankId = questionBankGetRequest.getId();

        // 拼接查询条件
        if (StringUtils.isNotBlank(searchText)) {
            queryWrapper.and(qw -> qw.like("title", searchText).or().like("tags", searchText));
        }
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                queryWrapper.like("tags", "\"" + tag + "\"");
            }
        }
        queryWrapper.eq(ObjectUtils.isNotEmpty(questionBankId), "id", questionBankId);
        queryWrapper.eq(ObjectUtils.isNotEmpty(userId), "userId", userId);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC),
                sortField);
        return queryWrapper;
    }

    @Override
    public Page<QuestionBankVO> getQuestionBankVOPage(Page<QuestionBank> questionBankPage, HttpServletRequest request) {
        List<QuestionBank> questionBankList = questionBankPage.getRecords();
        Page<QuestionBankVO> questionBankVOPage = new Page<>(questionBankPage.getCurrent(), questionBankPage.getSize(), questionBankPage.getTotal());
        if (CollUtil.isEmpty(questionBankList)) {
            return questionBankVOPage;
        }
        // 1. 关联查询用户信息
        Set<Long> userIdSet = questionBankList.stream().map(QuestionBank::getUserId).collect(Collectors.toSet());
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 填充信息
        List<QuestionBankVO> questionBankVOList = questionBankList.stream().map(questionBank -> {
            QuestionBankVO questionBankVO = QuestionBankVO.objToVo(questionBank);
            Long userId = questionBank.getUserId();
            User user = null;
            if (userIdUserListMap.containsKey(userId)) {
                user = userIdUserListMap.get(userId).get(0);
            }
            questionBankVO.setUser(userService.getUserVO(user));
            return questionBankVO;
        }).collect(Collectors.toList());
        questionBankVOPage.setRecords(questionBankVOList);
        return questionBankVOPage;
    }

    @Override
    public Boolean deleteBatchQuestionBank(DeleteRequest deleteRequest) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.in("id", deleteRequest.getIds());
        return remove(wrapper);
    }

    @Override
    public Page<QuestionBankVO> listQuestionBankVOByRecommend(QuestionBankRecommendRequest questionBankRecommendRequest, HttpServletRequest request) {
        // 获取每个用户喜欢的题库和题库数量
        // 获取所有的用户
        List<User> allUserList = userService.getAllUser();

        // 定义变量记录每个用户喜欢的题库/题库数量
        Map<Long, Set<Long>> userLikeQuestionBank = new HashMap<>();
        Map<Long, Integer> userLikeQuestionBankCount = new HashMap<>();
        // 遍历用户列表获取喜欢的题库
        for (User user : allUserList) {
            Set<Long> likeBankIds = new HashSet<>();
            List<AnswerResult> curUserAnswerResultList = answerResultService.getAnswerResultByUserId(user.getId());
            for (AnswerResult answerResult : curUserAnswerResultList) {
                likeBankIds.add(answerResult.getQuestionBankId());
            }
            userLikeQuestionBank.put(user.getId(), likeBankIds);
            userLikeQuestionBankCount.put(user.getId(), likeBankIds.size());
        }
        // 获取倒排表
        // 定义属性存储倒排表
        Map<Long, Set<Long>> questionBankLikedByUser = new HashMap<>();
        for (Map.Entry<Long, Set<Long>> likeEntrySet : userLikeQuestionBank.entrySet()) {
            Long userId = likeEntrySet.getKey();
            Set<Long> questionBankIds = likeEntrySet.getValue();
            for (Long questionBankId : questionBankIds) {
                Set<Long> userIds = questionBankLikedByUser.getOrDefault(questionBankId, new HashSet<>());
                userIds.add(userId);
                questionBankLikedByUser.put(questionBankId, userIds);
            }
        }
        // 获取协同过滤矩阵
        // 获取当前登录用户的用户ID
        Long loginUserId = userService.getLoginUser(request).getId();
        // 定义变量存储每个用户和当前用户共同感兴趣的题库的数量
        Map<Long, Integer> alsoLikeQuestionBankCount = new HashMap<>();
        for (Map.Entry<Long, Set<Long>> entry : questionBankLikedByUser.entrySet()) {
            Set<Long> userIds = entry.getValue();
            for (Long userId : userIds) {
                if (userId.equals(loginUserId)) {
                    for (Long otherId : userIds) {
                        if (!otherId.equals(loginUserId)) {
                            alsoLikeQuestionBankCount.put(otherId, alsoLikeQuestionBankCount.getOrDefault(otherId, 0) + 1);
                        }
                    }
                    break;
                }
            }
        }
        // 使用Jaccard公式计算相似度
        Map<Long , Double> similarMap = new HashMap<>();
        for (Map.Entry<Long, Integer> entry : alsoLikeQuestionBankCount.entrySet()) {
            Long otherUserId = entry.getKey();
            Double similar = alsoLikeQuestionBankCount.get(otherUserId) / Math.sqrt(userLikeQuestionBankCount.get(loginUserId) * userLikeQuestionBankCount.get(otherUserId));
            similarMap.put(otherUserId , similar);
        }

        // 获取前几个最相似的用户
        // 定义一个列表用于接受Map的数据，方便后续的排序操作
        List<Map.Entry<Long, Double>> sortList = new ArrayList<>(similarMap.entrySet());
        sortList.sort((o1, o2) -> Double.compare(o2.getValue(), o1.getValue()));
        int userNum = 10;
        // 定义Map记录最应该推荐的物品
        Map<Long, Double> recommendBankIds = new HashMap<>();
        for (int i = 0; i < userNum && i<sortList.size(); i++) {
            Map.Entry<Long, Double> similarUserLikeInfo = sortList.get(i);
            Long userId = similarUserLikeInfo.getKey();
            Double score = similarUserLikeInfo.getValue();
            for (Long bankId : userLikeQuestionBank.get(userId)) {
                if (userLikeQuestionBank.get(loginUserId).contains(bankId)) {
                    continue;
                }
                recommendBankIds.put(bankId, recommendBankIds.getOrDefault(bankId, 0.0) + score);
            }
        }
        // 获取前几个最喜欢的题库
        List<Map.Entry<Long , Double>> bankSortList = new ArrayList<>(recommendBankIds.entrySet());
        bankSortList.sort(((o1, o2) -> Double.compare(o2.getValue() , o1.getValue())));

        int current = questionBankRecommendRequest.getCurrent();
        int pageSize = questionBankRecommendRequest.getPageSize();
        int leftIndex = (current - 1) * pageSize;
        int rightIndex = current * pageSize-1;

        List<Long> ids = new ArrayList<>();
        for(int i = leftIndex ; i<=rightIndex;i++){
            if(i<0||i>=bankSortList.size()){
                break;
            }
            ids.add(bankSortList.get(i).getKey());
        }
        List<QuestionBank> questionBanks = this.listByIds(ids);
        List<QuestionBankVO> questionBankVOList = new ArrayList<>();
        for (QuestionBank questionBank : questionBanks) {
            questionBankVOList.add(QuestionBankVO.objToVo(questionBank));
        }
        Page<QuestionBankVO> result = new Page<>();
        result.setRecords(questionBankVOList);
        result.setCurrent(1);
        result.setPages(pageSize);
        result.setTotal(pageSize);
        return result;
    }
}




